using System;
using System.IO;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using WcfExtensions.ServiceModel.Channels;

namespace WcfExtensions.ServiceModel.TestClient.Scenarios.Basic
{
    internal static class BasicScenario
    {
        public static void Run()
        {
            RunScenario(new Uri("http://localhost:999/testservice"), CreateBinding());
            RunScenario(new Uri("net.pipe://localhost/testservice"), CreateNpBinding());
            RunScenario(new Uri("net.tcp://localhost:99/testservice"), CreateTcpBinding());
        }

        private static void RunScenario(Uri uri, Binding binding)
        {
            var writer = new StringWriter();
            for (int i = 0; i < 5000; ++i)
            {
                writer.Write(Guid.NewGuid());
            }

            var msg = new NewsMessage {TimeStamp = DateTime.UtcNow, Message = writer.ToString()};

            using (var host = new ServiceHost(typeof(BasicService), uri))
            {
                host.Description.Behaviors.Find<ServiceDebugBehavior>().IncludeExceptionDetailInFaults = true;
                host.AddServiceEndpoint(typeof(IBasicService), binding, uri);
                host.Open();


                IBasicService channel = new ChannelFactory<IBasicService>(binding, new EndpointAddress(uri)).CreateChannel(new EndpointAddress(uri));

                Console.WriteLine(channel.SendMessage(msg));
                channel.Ping2(Message.CreateMessage(MessageVersion.Default, "http://tempuri.org/IBasicService/Ping2", msg));
                channel.Ping(DateTime.UtcNow);

                ((IClientChannel)channel).Close();

                host.Close();
            }
        }

        private static CustomBinding CreateBinding()
        {
            var element = new CompressionBindingElement
                              {
                                  Algorithm = CompressionAlgorithm.Deflate,
                                  Level = CompressionLevel.Maximum
                              };

            var binding = new CustomBinding();
            binding.Elements.Add(element);
            binding.Elements.Add(SecurityBindingElement.CreateSspiNegotiationBindingElement());

            var encoder = new TextMessageEncodingBindingElement();
            encoder.ReaderQuotas.MaxStringContentLength = 1024*1024*50;
            binding.Elements.Add(encoder);

            var transport = new HttpTransportBindingElement
                                {
                                    MaxBufferSize = 1000000,
                                    MaxReceivedMessageSize = 1000000
                                };
            binding.Elements.Add(transport);
            return binding;
        }

        private static CustomBinding CreateTcpBinding()
        {
            var binding = new CustomBinding();
            binding.Elements.Add(new CompressionBindingElement());

            var e = new BinaryMessageEncodingBindingElement();
            e.ReaderQuotas.MaxStringContentLength = 10000000;
            binding.Elements.Add(e);

            var transport = new TcpTransportBindingElement();
            transport.MaxReceivedMessageSize = transport.MaxBufferSize = 1000000;
            binding.Elements.Add(transport);
            return binding;
        }

        private static CustomBinding CreateNpBinding()
        {
            var binding = new CustomBinding();
            binding.Elements.Add(new CompressionBindingElement());
            var e = new BinaryMessageEncodingBindingElement();
            e.ReaderQuotas.MaxStringContentLength = 10000000;

            binding.Elements.Add(e);
            var transport = new NamedPipeTransportBindingElement
                                {
                                    MaxBufferSize = 10000000,
                                    MaxReceivedMessageSize = 10000000
                                };


            binding.Elements.Add(transport);
            return binding;
        }
    }
}